package com.globefrog.common.spring;

import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.SingletonBeanRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;

/**
 * @author : caijinbang
 * @date : Create in 2021-05-13
 */
public class SpringObjectFactory {

  private ApplicationContext applicationContext;

  public SpringObjectFactory() {
  }

  public <T> T createBean(Class<T> beanClass) {
    return this.applicationContext.getAutowireCapableBeanFactory().createBean(beanClass);
  }

  public Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) {
    return this.applicationContext.getAutowireCapableBeanFactory()
        .createBean(beanClass, autowireMode, dependencyCheck);
  }

  public <T> T getBean(Class<T> beanClass) {
    return this.applicationContext.getBean(beanClass);
  }

  public <T> T getBean(Class<T> beanClass, Object... args) {
    return this.applicationContext.getBean(beanClass, args);
  }

  public <T> T getBean(String name) {
    return (T) this.applicationContext.getBean(name);
  }

  public <T> List<T> getBeans(Class<T> beanClass) {
    return new ArrayList(this.applicationContext.getBeansOfType(beanClass).values());
  }

  public <T> T initializeBean(T bean) {
    return this.initializeBean(bean, bean.getClass().getName());
  }

  public <T> T initializeBean(T bean, String beanName) {
    AutowireCapableBeanFactory beanFactory = this.applicationContext
        .getAutowireCapableBeanFactory();
    beanFactory.autowireBean(bean);
    return (T) beanFactory.initializeBean(bean, beanName);
  }

  public void registerSingletonBean(String beanName, Object bean) {
    SingletonBeanRegistry registry = (SingletonBeanRegistry) this.applicationContext
        .getAutowireCapableBeanFactory();
    registry.registerSingleton(beanName, bean);
  }

  public void registerSingletonBean(String beanName, Class beanClass) {
    this.registerBean(beanName, beanClass, "singleton");
  }

  public void registerBean(String beanName, Class beanClass, String scope) {
    GenericBeanDefinition definition = new GenericBeanDefinition();
    definition.setBeanClass(beanClass);
    definition.setScope(scope);
    BeanDefinitionRegistry registry = (BeanDefinitionRegistry) this.applicationContext
        .getAutowireCapableBeanFactory();
    registry.registerBeanDefinition(beanName, definition);
  }

  @Autowired
  public void setApplicationContext(ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
    AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext
        .getAutowireCapableBeanFactory();
    Assert.isTrue(autowireCapableBeanFactory instanceof BeanDefinitionRegistry,
        "autowireCapableBeanFactory should be BeanDefinitionRegistry");
    Assert.isTrue(autowireCapableBeanFactory instanceof SingletonBeanRegistry,
        "autowireCapableBeanFactory should be BeanDefinitionRegistry");
  }
}
